﻿using MSL.Tool;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;

namespace TimedTask.Tools
{
    /// <summary>
    /// HTML相关类<br/>
    /// add by mashanlin 2013-6-25 <br/>
    /// </summary>
    public class HtmlHelper
    {
        #region 变量

        //图片正则
        //private const string REG_IMG = "<img[^>]+src=\\s*(?:'(?<src>[^']+)'|\"(?<src>[^\"]+)\"|(?<src>[^>\\s]+))\\s*[^>]*>";
        //图片正则
        private const string REG_IMG = "src=['\"](?<src>[^'\"]*?\\.({0}))['\"]|(?<src>http.*?\\.({1}))";
        //链接
        private const string REG_LINK = @"<a(.*?)href=\s*(?:'(?<href>[^']+)'|""(?<href>[^""]+)""|(?<href>[^>\s]+))\s*[^>]*>";
        //private const string REG_LINK1 = "<a(.*?)href=\\s*['\"](?<href>[^\"']+)['\"][^>]*>(?<title>(?:[\\s\\S]*?))</a>";
        //取文件
        private const string FILE_HREF = "<a.*?href=['\"](?<href>.*?\\.({0}))['\"]";

        #endregion

        #region 获得链接

        /// <summary>
        /// 多个链接
        /// </summary>
        /// <param name="input">输入内容</param>
        public static ArrayList GetLinks(string input)
        {
            ArrayList al = new ArrayList();

            Regex re = new Regex(REG_LINK, RegexOptions.IgnoreCase | RegexOptions.Multiline);//| RegexOptions.IgnorePatternWhitespace
            MatchCollection mcs = re.Matches(input);

            foreach (Match mc in mcs)
            {
                string[] link = new String[3];
                link[0] = mc.Groups["title"].Value;
                link[1] = mc.Groups["href"].Value;
                al.Add(link);
            }
            return al;
        }
        #endregion

        /// <summary>
        /// 过滤Html标记
        /// </summary>
        /// <param name="htmlCode">源码</param>
        /// <param name="leaveTags">保留标签，如：img|p|br|a</param>
        /// <returns></returns>
        public static string ClearHtml(string htmlCode)
        {
            return Regex.Replace(htmlCode, @"<[^>]*>", "");
        }

        #region 获取页面内容
        /// <summary>
        /// 获取网页源码
        /// </summary>
        /// <param name="url">链接</param>
        /// <returns></returns>
        public static string GetHtml(string url)
        {
            return GetHtml(ref url, "");
        }
        /// <summary>
        /// 获取网页源码
        /// </summary>
        /// <param name="url">链接</param>
        /// <param name="pageEncode">文本编码:utf-8 gb2312</param>
        /// <returns></returns>
        public static string GetHtml(ref string url, string pageEncode)
        {
            string content = "";
            try
            {
                HttpWebResponse response = GetResponse(url);
                if (response == null)
                {
                    return content;
                }
                url = response.ResponseUri.AbsoluteUri;
                Stream stream = response.GetResponseStream();
                byte[] buffer = GetContent(stream);
                stream.Close();
                stream.Dispose();
                string charset = "";
                if (pageEncode == null || pageEncode == "")
                {
                    //首先，从返回头信息中寻找
                    string ht = response.GetResponseHeader("Content-Type");
                    response.Close();
                    string regCharSet = "[\\s\\S]*charset=(?<charset>[\\S]*)";
                    Regex r = new Regex(regCharSet, RegexOptions.IgnoreCase);
                    Match m = r.Match(ht);
                    charset = (m.Captures.Count != 0) ? m.Result("${charset}") : "";
                    if (charset == "-8") charset = "utf-8";

                    if (charset == "")//找不到，则在文件信息本身中查找
                    {
                        //先按gb2312来获取文件信息
                        content = System.Text.Encoding.GetEncoding("gb2312").GetString(buffer);
                        regCharSet = "(<meta[^>]*charset=(?<charset>[^>'\"]*)[\\s\\S]*?>)|(xml[^>]+encoding=(\"|')*(?<charset>[^>'\"]*)[\\s\\S]*?>)";
                        r = new Regex(regCharSet, RegexOptions.IgnoreCase);
                        m = r.Match(content);
                        if (m.Captures.Count == 0)//没办法，都找不到编码，只能返回按"gb2312"获取的信息
                        {
                            return content;
                        }
                        charset = m.Result("${charset}");
                    }
                }
                else
                {
                    response.Close();
                    charset = pageEncode.ToLower();
                }
                try
                {
                    content = System.Text.Encoding.GetEncoding(charset).GetString(buffer);
                }
                catch (ArgumentException)
                {//指定的编码不可识别
                    content = System.Text.Encoding.GetEncoding("gb2312").GetString(buffer);
                }
            }
            catch
            {
                content = "";
            }
            return content;
        }

        #endregion

        #region 补全链接
        /// <summary>
        /// 基于baseUrl，补全html代码中的链接 masl 2014-3-13 添加
        /// </summary>
        /// <param name="baseUrl"></param>
        /// <param name="html"></param>
        public static string FixUrl(string baseUrl, string html)
        {
            html = Regex.Replace(html, "(?is)(href|src)=(\"|\')([^(\"|\')]+)(\"|\')", (match) =>
            {
                string org = match.Value;
                string link = match.Groups[3].Value;
                if (link.StartsWith("http"))
                {
                    return org;
                }
                try
                {
                    Uri uri = new Uri(baseUrl);
                    Uri thisUri = new Uri(uri, link);
                    string fullUrl = String.Format("{0}=\"{1}\"", match.Groups[1].Value, thisUri.AbsoluteUri);
                    return fullUrl;
                }
                catch (Exception)
                {
                    return org;
                }
            });
            return html;
        }
        #endregion

        #region 替换指定内容

        /// <summary>
        /// 替换指定内容
        /// </summary>
        /// <param name="input">输入内容</param>
        /// <param name="pattern">表达式字符串</param>
        /// <param name="replaceValue">替换值</param>
        /// <param name="groupIndex">分组序号, 0代表不分组</param>
        public static string Replace(string input, string pattern, string replaceValue, int groupIndex)
        {
            Regex re = new Regex(pattern, RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace);
            MatchCollection mcs = re.Matches(input);
            foreach (Match mc in mcs)
            {
                if (groupIndex > 0)
                {
                    input = input.Replace(mc.Groups[groupIndex].Value, replaceValue);
                }
                else
                {
                    input = input.Replace(mc.Value, replaceValue);
                }
            }
            return input;
        }
        #endregion

        #region 获得特定内容

        /// <summary>
        /// 图片地址
        /// </summary>
        /// <param name="input">输入内容</param>
        public static List<String> GetImages(string input, string fileSuffix)
        {
            var list = Helper.GetList(input, String.Format(REG_IMG, fileSuffix, fileSuffix), "src");
            List<string> imgs = new List<string>();
            if (list != null && list.Count > 0)
                foreach (var src in list)
                {
                    if (imgs.Contains(src))
                        continue;

                    imgs.Add(src);
                }
            return imgs;
        }

        /// <summary>
        /// 文件地址
        /// </summary>
        /// <param name="input">输入内容</param>
        /// <param name="fileSuffix">文件后缀，格式：rar|zip|7z</param>
        public static List<String> GetFiles(string input, string fileSuffix)
        {
            try
            {
                var list = Helper.GetList(input, String.Format(FILE_HREF, fileSuffix), "href");
                List<string> files = new List<string>();
                if (list != null && list.Count > 0)
                    foreach (var src in list)
                    {
                        if (files.Contains(src))
                            continue;

                        files.Add(src);
                    }
                return files;
            }
            catch (Exception e)
            {
                LogHelper.SaveErrorLog("获取文件地址 GetFiles", e);
                return null;
            }
        }

        #endregion 获得特定内容

        #region 私有方法

        private static HttpWebResponse GetResponse(string url)
        {
            int timeOut = 10000;
            bool isCookie = false;
            bool isRepeat = false;
            Uri target = new Uri(url);
            ReCatch:
            try
            {
                HttpWebRequest resquest = (HttpWebRequest)WebRequest.Create(target);
                resquest.MaximumResponseHeadersLength = -1;
                resquest.ReadWriteTimeout = 120000;//120秒就超时
                resquest.Timeout = timeOut;
                resquest.MaximumAutomaticRedirections = 50;
                resquest.MaximumResponseHeadersLength = 5;
                resquest.AllowAutoRedirect = true;
                if (isCookie)
                {
                    resquest.CookieContainer = new CookieContainer();
                }
                resquest.UserAgent = "Mozilla/6.0 (compatible; MSIE 6.0; Windows NT 5.1)";
                return (HttpWebResponse)resquest.GetResponse();
            }
            catch (WebException)
            {
                if (!isRepeat)
                {
                    isRepeat = true;
                    isCookie = true;
                    goto ReCatch;
                }
                return null;
            }
            catch
            {
                return null;
            }
        }
        private static byte[] GetContent(Stream stream)
        {
            ArrayList al = new ArrayList();
            try
            {
                byte[] buffer = new byte[4096];
                int count = stream.Read(buffer, 0, 4096);
                while (count > 0)
                {
                    for (int i = 0; i < count; i++)
                    {
                        al.Add(buffer[i]);
                    }
                    count = stream.Read(buffer, 0, 4096);
                }
            }
            catch { }

            return (byte[])al.ToArray(System.Type.GetType("System.Byte"));
        }

        #endregion
    }
}
